#pragma once

#include "../Main/Standard.h"
#include "../Container/DynamicArray.h"

#include "IFactoryAble.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	InputSystem  </Summary>
/// 
/// <purpose>	Engine system used to contain and control input	</purpose>
////////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class StackFactory
{
	/// <Summary> Stack of objects currently ready to be reused </Summary>
	DynamicArray<T*> objectStack;

private:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Makes copy and assignment unavailable to this class </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	DISALLOW_COPY_AND_ASSIGN(StackFactory)

public:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Default constructor </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	StackFactory() : objectStack(100) { }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Default destructor </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	~StackFactory();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets a new object ready to be used </Summary>
	///
	/// <Return>	The object </Return>
	/// 
	/// <Remarks>	This should always be used instead of calling new in reference to T	</Remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	T* NewObject();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Return an unused object to this factory </Summary>
	///
	/// <Param name="object">	The object </Param>
	/// 
	/// <Remarks>	This should always be used instead of calling delete in reference to T	</Remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void DeleteObject(T* object);
};








////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Default destructor </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
StackFactory<T>::~StackFactory(void)
{
	while(objectStack.GetSize() > 0)
	{
		T* object = objectStack.Pop_Back();
		delete object;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Gets a new object ready to be used </Summary>
///
/// <Return>	The object </Return>
/// 
/// <Remarks>	This should always be used instead of calling new in reference to T	</Remarks>
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
T* StackFactory<T>::NewObject()
{
	if(objectStack.GetSize() > 0)
	{
		T* obj = objectStack.Pop_Back();
		obj->Clear();
		return obj;
	}

	return new T;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Return an unused object to this factory </Summary>
///
/// <Param name="object">	The object </Param>
/// 
/// <Remarks>	This should always be used instead of calling delete in reference to T	</Remarks>
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
void StackFactory<T>::DeleteObject(T* object)
{
	if(object == NULL)
		return;

	objectStack.Push_Back(object);
}